package com.hhsjdesign.dynamicui.asm.v3

import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import com.hhsjdesign.dynamicui.asm.Logger
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FileUtils
import org.gradle.api.Project


/**
 * 处理字节码
 * 1,已经产生的jar包扫描到自动生成的哪些注解类,添加到一个列表中
 * 2,扫描到最终自动调用的类，（也是从jar中扫描到）,插入字节码,字节码来自于找到列表中的类的方法
 */
class DynamicUiTransformV3 extends Transform {

    Project project
    //扫描配置
    static ArrayList<ScanSettingV3> registerList
    //目标asm操作文件
    static File targetAsmClass;

    DynamicUiTransformV3(Project project) {
        this.project = project
    }

    @Override
    String getName() {
        return ScanSettingV3.PLUGIN_NAME
    }

    //类型 字节码
    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    //扫描位置 整个工程所有的位置

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return false
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        super.transform(transformInvocation)
        println("开始自定义transform")

        long startTime = System.currentTimeMillis()

        if (!transformInvocation.isIncremental()) {
            transformInvocation.outputProvider.deleteAll()
        }

//        doTransform(transformInvocation.context, transformInvocation.referencedInputs,
//                transformInvocation.outputProvider, transformInvocation.isIncremental())

        // OutputProvider管理输出路径，如果消费型输入为空，你会发现OutputProvider == null
        TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();

        transformInvocation.inputs.each { TransformInput input ->


            // 处理Jar
            input.jarInputs.each { JarInput jarInput ->
                processJarInput(jarInput, outputProvider)
            }

            // 处理源码文件
            input.directoryInputs.each { DirectoryInput directoryInput ->
                processDirectoryInputs(directoryInput, outputProvider)
            }
        }

        println('Scan finish, current cost time ' + (System.currentTimeMillis() - startTime) + "ms")

        //找到了最终的类:
        if (targetAsmClass != null) {
            registerList.each { ext ->
                println('Insert register code to file ' + targetAsmClass.absolutePath)

                if (ext.classList.isEmpty()) {
                    println("No class implements found for interface:" + ext.interfaceName)
                } else {
                    ext.classList.each {
                        println(it)
                    }
                    //终极操作:插入字节码
                    RegisterCodeGeneratorV3.insertInitCodeTo(ext)
                }
            }
        }

        Logger.i("Generate code finish, current cost time: " + (System.currentTimeMillis() - startTime) + "ms")

        println "结束自定义transform"
    }


    /**
     * 处理jar包,即已经打包的问题的class文件
     * @param jarInput
     * @param outputProvider
     */
    static void processJarInput(JarInput jarInput, TransformOutputProvider outputProvider) {
        Logger.i('Start scan register info in jar file.')

        // 重命名输出文件（同目录copyFile会冲突）

//        if (!jarInput.file.getAbsolutePath().contains("build")) {
//            return
//        }
//        println "原始文件jar文件名称:${jarInput.file.getAbsolutePath()}"

        String destName = jarInput.name
        // rename jar files
        def hexName = DigestUtils.md5Hex(jarInput.file.absolutePath)
        if (destName.endsWith(".jar")) {
            destName = destName.substring(0, destName.length() - 4)
        }
        // input file
        File src = jarInput.file
        // output file
        File dest = outputProvider.getContentLocation(
                destName + "_" + hexName,
                jarInput.contentTypes,
                jarInput.scopes,
                Format.JAR)

        //scan jar file to find classes
        if (ScanUtilV3.shouldProcessPreDexJar(src.absolutePath)) {
            //扫描所有的jar
            ScanUtilV3.scanJar(src, dest)
        }

//        File dest = outputProvider.getContentLocation(
//                jarInput.getFile().getAbsolutePath(),
//                jarInput.getContentTypes(),
//                jarInput.getScopes(),
//                Format.JAR)

        // to do some transform
//        println "目标文件jar文件名称:${dest.getAbsolutePath()}"

        FileUtils.copyFile(src, dest)

        // 将修改过的字节码copy到dest，就可以实现编译期间干预字节码的目的了
//        FileUtils.copyFile(jarInput.getFile(), dest)
    }

    static void processDirectoryInputs(DirectoryInput directoryInput, TransformOutputProvider outputProvider) {
        Logger.i('Start scan register info in directory file.')


        // 将修改过的字节码copy到dest，就可以实现编译期间干预字节码的目的了
//        FileUtils.copyDirectory(directoryInput.getFile(), dest)
        File src = directoryInput.file

        File dest = outputProvider.getContentLocation(
                directoryInput.name,
                directoryInput.contentTypes,
                directoryInput.scopes,
                Format.DIRECTORY)
        // 建立文件夹
//        FileUtils.forceMkdir(dest)

        Logger.i "普通文件目录名称:${dest.getAbsolutePath()}"

        String root = directoryInput.file.absolutePath
        if (!root.endsWith(File.separator)) {
            root += File.separator
        }

        directoryInput.file.eachFileRecurse { File file ->
            boolean leftSlash = File.separator == '/'

            def path = file.absolutePath.replace(root, '')
            if (!leftSlash) {
                path = path.replaceAll("\\\\", "/")
            }

            //扫描所有的类文件
            if (file.isFile() && ScanUtilV3.shouldProcessClass(path)) {
                ScanUtilV3.scanClassFile(file)
            }
        }

        // copy to dest
        FileUtils.copyDirectory(src, dest)
    }

}